package ferp.core.game;

import ferp.core.card.Card;
import ferp.core.mode.Mode;
import ferp.core.player.Player;
import ferp.core.state.State;

/**
 * User: olegs
 * Date: 09/11/2014 14:05
 */
public class Restorer
{
  public static void execute(Game.Listener listener, Game g, Settings settings)
  {
    restoreLastTrickMenu(listener, g);
    restoreFirstHand(listener, g, settings);
    restorePlayers(listener, g, settings);
    restoreTalon(listener, g, settings);

    // the game can be in the "ShowPool2" state when the play was ended early (offers)
    // this is most likely a dead code,
    // if game is showPool1 state the input options must be cleared, otherwise PoolDialog won't be shown
    if (g.state() == State.showPool1 || g.state() == State.showPool2)
    {
      g.options.clear();
      g.set(State.showPool1);
    }

    // Note: this is for compliance with the old "game save" implementation
    if (g.state() == State.showPool1 || g.state() == State.end || g.state() == State.fastMoving || g.state() == State.showInitialPosition)
    {
      listener.onGameRestoreEnd(g);

      return;
    }
    // end of compliance block

    if (Mode.isMoving(g.mode()) && g.state() != State.initialize)
    {
      // adjust round number as its value may remain from the previous mode (we did not go through Mode.initialize)
      g.rounds = g.trick.list().size();

      restoreMisere(listener, g, settings);
      restoreTrick(listener, g);

      // start game resume task only in case some player still holds card(s)
      if (g.getHand(0).current != 0 || g.getHand(1).current != 0 || g.getHand(2).current != 0)
        listener.onResolverRestoreRequested(g, settings);
      else
        listener.onGameRestoreEnd(g);
    }
    else
      listener.onGameRestoreEnd(g);
  }

  private static void restoreLastTrickMenu(Game.Listener listener, Game g)
  {
    listener.enableLastTrickMenu(g.trick.last != 0);
  }

  private static void restoreFirstHand(Game.Listener listener, Game g, Settings settings)
  {
    if (g.mode().showFirstHand(g, settings))
      listener.showFirstHand(g.getFirstHandPlayer());
    else
      listener.hideFirstHand();
  }

  private static void restorePlayers(Game.Listener listener, Game g, Settings settings)
  {
    for (Player p : g.players())
    {
      Game.BidData bid = g.getBid(p.id());

      listener.showPlayerCards(g, settings, p.id());

      if (bid.visible && bid.current != null)
        listener.showBid(p, bid, false);

      // assign correct number of tricks for a player to resolve transient state/mode resuming
      //if (moving)
      //  g.setTricks(p.id(), g.trick.tricks(p.id(), g.trump()));

      listener.setTrickCount(p.id(), g.getTricks(p.id()));

      // the statement below is to resolve the following case:
      // 1. restore game at round end, i.e. 3 cards in trick when next move should be done by human
      // 2. start to move card, but don't commit it
      // 3. open settings activity and then close it without change anything
      // 4. resolved problem: despite game is restored and trick is shown with 3 cards human is able to move card before trick disappear
      // in other words, we shouldn't relay on the fact the TableView is always created from the scratch when game is restored
      listener.disablePlayerCards(p.id());
    }
  }

  private static void restoreTalon(Game.Listener listener, Game g, Settings settings)
  {
    listener.setTalon(g.talon());

    for (int i = 0; i < Game.TALON_SIZE; ++i)
      switch (g.mode().getTalonCardState(g, settings, i))
      {
        case FACE_DOWN:
          listener.closeTalonCard(i);
          break;

        case FACE_UP:
          listener.openTalonCard(i);
          break;

        case HIDDEN:
          listener.hideTalonCard(i);
          break;
      }
  }

  private static void restoreMisere(Game.Listener listener, Game g, Settings settings)
  {
    if (g.bid != null && g.bid.isMisere() && g.declarer() != g.human())
    {
      listener.showMisereDesk(g, settings, g.getDeclarerHand().initial | g.getTalonHash(0) | g.getTalonHash(1));

      for (int trick : g.trick.list())
        markMisereMove(listener, Trick.card(trick, g.declarer()));

      if (g.trick.current != 0)
        markMisereMove(listener, Trick.card(g.trick.current, g.declarer()));
    }
  }

  private static void markMisereMove(Game.Listener listener, Card c)
  {
    if (c != null)
      listener.markMisereMove(c.hash);
  }

  private static void restoreTrick(Game.Listener listener, Game g)
  {
    if (g.trick.current != 0)
      listener.showTrick(g.trick.current);

    // assign correct hand and current player to resolve transient state/mode resuming
    while (g.hand < Trick.size(g.trick.current))
    {
      ++g.hand;
      g.player.current = Game.next(g.player.current);
    }
  }
}
